using JamesZhao.Engine.Graphics.Effects;
using SlimDX.Direct3D11;
using SlimMath;

namespace JamesZhao.Engine.Graphics.Visuals
{
    public abstract class Drawable
    {
        public Matrix LocalToWorldMatrix { get; set; }
        public Material Material { get; set; }
        
        public abstract void RenderWithGpuProgram(GraphicsDevice device, GpuProgram gpuProgram);
        protected void ApplyCameraConstants(GpuProgram gpuProgram, Camera camera)
        {
            gpuProgram.WorldViewProjectionVar.SetMatrix(LocalToWorldMatrix*camera.ViewProjectionMatrix);
            gpuProgram.WorldViewVar.SetMatrix(LocalToWorldMatrix*camera.ViewMatrix);
            gpuProgram.ViewVar.SetMatrix(camera.ViewMatrix);
            Matrix invProj = camera.Lens.ProjectionMatrix;
            invProj.Invert();
            gpuProgram.InverseProjectionVar.SetMatrix(invProj);
        }

        public virtual void Render(GraphicsDevice device, Camera camera)
        {
            RenderWithGpuProgram(device, camera, Material);
        }

        public virtual void RenderWithGpuProgram(GraphicsDevice device, Camera camera, GpuProgram gpuProgram)
        {
            ApplyCameraConstants(gpuProgram, camera);
            RenderWithGpuProgram(device, gpuProgram);
        }

        protected static void RenderPasses(GraphicsDevice device, GpuProgram gpuProgram, GeometryBuffer buffer)
        {
            EffectTechnique technique = gpuProgram.Effect.GetTechniqueByIndex(0);
            EffectPass pass = technique.GetPassByIndex(0);

            for (int i = 0; i < technique.Description.PassCount; ++i)
            {
                pass.Apply(device.ImmediateContext);
                device.ImmediateContext.DrawIndexed(buffer.TriangleCount * 3, 0, 0);
            }
        }
    }
}